#!/usr/bin/env python

import errno
import os
import pexpect
import re
import string
import threading
import time

import pygtk
import gobject
import gtk
import gtk.glade

class UnisonProfile:
    treestore = gtk.ListStore(str)
    
    def __init__(self):
        self.treestore.append(['fluence-test'])
        pass

    def save(self):
        try:
            os.mkdir("/home/wlach/.unison")
        except OSError, e:
            # Ignore directory exists error
            if e.errno <> errno.EEXIST:
                raise
            
        proffile = open(os.path.join("/home/wlach/.unison", "fluence.prf"),
                        'w')
        proffile.write("# This file has been automatically generated by "
                       "fluence: DO NOT EDIT!\n")
        proffile.write("root = /home/wlach/\n")
        proffile.write("root = /tmp/wlach/\n")
        proffile.write("\n")

        row = self.treestore.get_iter_first()
        while row:
            print "Adding path: " + self.treestore[row][0]
            proffile.write("path = " + self.treestore[row][0] + "\n")
            row = self.treestore.iter_next(row)

        proffile.write("\n");
        proffile.close()

class SyncWindow:
    def __init__(self, mainwindow):
        self.dialog = gtk.Dialog("Synchronizing files", mainwindow,
                            gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                            (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT))
        self.dialog.set_property("has-separator", False)

        title_label = gtk.Label()
        title_label.set_markup("<big><b>Synchronizing files</b></big>")
        title_label.set_alignment(0, 0)
        title_label.set_padding(8, 8)

        from_label = gtk.Label()
        from_label.set_markup("<b>From:</b> " "foo")
        from_label.set_alignment(0, 0)
        from_label.set_padding(8, 2)

        to_label = gtk.Label()
        to_label.set_markup("<b>To:</b> " "foo")
        to_label.set_alignment(0, 0)
        to_label.set_padding(8, 2)

        self.progressbar = gtk.ProgressBar()
        #self.progressbar.set_text("Synchronizing file: x of y (0:00 remaining)")
        progress_align = gtk.Alignment(1, 1, 1, 1)
        progress_align.set_padding(2, 2, 8, 8)
        progress_align.add_with_properties(self.progressbar)
        
        self.dialog.vbox.pack_start(title_label, True)
        self.dialog.vbox.pack_start(from_label, False)
        self.dialog.vbox.pack_start(to_label, False)
        self.dialog.vbox.pack_start(progress_align, False)

    def destroy_soon_cb(self):
        self.dialog.destroy()
        return False

    def destroy_soon(self):
        gobject.timeout_add(2000, self.destroy_soon_cb)
        
    def show(self):
        self.dialog.show_all()

class Synchronizer(threading.Thread):
    def __init__(self, syncwindow):
        threading.Thread.__init__(self) 
        self.syncwindow = syncwindow
        pass

    def run(self):
        # control here should pass to a thread..
        self.unison = pexpect.spawn('unison -batch fluence')
        print "Syncing.."
        self.percent = 0.0

        # read one byte at a time..        
        self.line = ''
        while self.poll_child():
            pass
        self.syncwindow.destroy_soon()

    def update_progress(self, percent):
        #print "Updating progress.." + str(float(self.counter)/100000.0)
        self.syncwindow.progressbar.set_fraction(percent/100.0)
        return False
    
    def poll_child(self):
       
        try:
            l = self.unison.read_nonblocking(1, 0)
            if l == '\r' or l == '\n':
                print "READ: " + self.line
                m = re.search('(\d+)%', self.line)
                if m:
                    percent = float(m.group(1))
                    gobject.idle_add(self.update_progress, percent)
                    print "Match found in line: " + str(percent)
                elif re.search('Nothing to do: replicas have not changed ' +
                               'since last sync.', self.line):
                    percent = 100.0
                    gobject.idle_add(self.update_progress, percent)
                else:
                    print "No match"
                self.line = ''
            else:
                self.line += l
            return 1
        except pexpect.EOF:
            return 0
        except pexpect.TIMEOUT:
            return 1            
                
class MainWindow:

    def __init__(self):
        # create a new window
        self.xml = gtk.glade.XML("mainwindow.glade")

        self.dialog = self.xml.get_widget("mainwindow")
        self.dialog.connect ("destroy", gtk.main_quit)
        #self.dialog.set_default_response (gtk.RESPONSE_ACCEPT)        

        # folders in a unison profile
        self.uprofile = UnisonProfile()
        self.folderview = self.xml.get_widget("folderview")
        column = gtk.TreeViewColumn ("Folders", gtk.CellRendererText(), text=0)
        self.folderview.append_column (column)
        self.folderview.set_model(self.uprofile.treestore)

        # the button to add a folder
        self.add_folder_button = self.xml.get_widget("addfolder")
        self.add_folder_button.connect("clicked", self.__add_folder_button_clicked)

        # the button to synchronize
        
        self.xml.get_widget("syncbutton").connect("clicked", self.__sync_button_clicked)

        # and the window
        self.dialog.show_all()

    def __add_folder_button_clicked(self, button):
        filechooser = gtk.FileChooserDialog("Add folder", self.dialog,
                                            gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
                                            (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                             gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT))
        response = filechooser.run()
        if response == gtk.RESPONSE_ACCEPT:
            m = re.search('file:///home/wlach/(.*)', filechooser.get_uri())
            if m:
                self.uprofile.treestore.append([m.group(1)])
            else:
                print "Invalid URI!!"
                
        filechooser.destroy()

    def __sync_button_clicked(self, button):
        print "Sync button clicked!"
        self.uprofile.save()
        print "Created syncwindow"
        self.syncwindow = SyncWindow(self.dialog)
        print "Creating synchronizer"
        self.synchronizer = Synchronizer(self.syncwindow)
        self.synchronizer.start()
        print "Created synchronizer"
        self.syncwindow.show()
        print "Syncwindow on display"
    
    def main(self):
        # All PyGTK applications must have a gtk.main(). Control ends here
        # and waits for an event to occur (like a key press or mouse event).
        gtk.main()

if __name__ == "__main__":
    gobject.threads_init()
    mainwindow = MainWindow()
    mainwindow.main()
